/**
 * Copyright (c) 2006
 *      OpenAVS Developers. All Rights Reserved.
 *
 * Copyright (c) 2005-2006
 *      NSCC. All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/**
 * ! \file "stream.c"
 *   \brief Functions related to streaming handling.
 */

#include "define.h"
#include "stream.h"
#include "vlc.h"
#include "global.h"
#include "macroblock.h"
#include "loopfilter.h"

AVS_DWORD SeqenceHeader(const AVS_BYTE* pbData, AVS_DWORD dwDataLen, SEQENCEINFO* Info)
{
	DWORD Left;
	const AVS_BYTE* pbCurrent = pbData;
	AVS_DWORD   bitOffset = 32;
	AVS_DWORD profile_id            = read_bits(pbCurrent, &bitOffset, 8);
	AVS_DWORD level_id              = read_bits(pbCurrent, &bitOffset, 8);
	AVS_BOOL  progressive_sequence  = read_bits(pbCurrent, &bitOffset, 1);
	AVS_DWORD horizontal_size       = read_bits(pbCurrent, &bitOffset, 14);
	AVS_DWORD vertical_size         = read_bits(pbCurrent, &bitOffset, 14);
	AVS_DWORD chromat_format        = read_bits(pbCurrent, &bitOffset, 2);
	AVS_DWORD sample_precision      = read_bits(pbCurrent, &bitOffset, 3);
	AVS_DWORD aspect_ratio          = read_bits(pbCurrent, &bitOffset, 4);
	AVS_DWORD frame_rate_code       = read_bits(pbCurrent, &bitOffset, 4);
	AVS_DWORD bit_rate_lower        = read_bits(pbCurrent, &bitOffset, 18);
	AVS_BOOL  market_bit            = read_bits(pbCurrent, &bitOffset, 1);
	AVS_DWORD bit_rate_upper        = read_bits(pbCurrent, &bitOffset, 12);
	AVS_BOOL  low_dlay              = read_bits(pbCurrent, &bitOffset, 1);

	if (dwDataLen < 18)
		return AVS_NOT_ENOUGH_DATA;

	FindNextPicOrEndStartCode(pbData, dwDataLen, &Left);

	Info->dwProfile = profile_id;
	Info->dwLevel = level_id;
	Info->bProgressive = progressive_sequence;
	Info->dwWidth = horizontal_size;
	Info->dwHeight = vertical_size;
	Info->fFrameRate = fPictureRates[frame_rate_code];
	Info->dwChromaFormat = chromat_format;
	Info->dwAspectRatio = aspect_ratio;
	Info->bLowDelay = low_dlay;

	Info->dwMbWidth = (horizontal_size + 15) / 16;
	Info->dwMbHeight = (vertical_size + 15) / 16; //??? 
#if PRINTINFO
/*		printf("Senqence Header detail:\n\tProfile_id           : %d\n\tLevel_id             : %d\n",Info->dwProfile, Info->dwLevel);
		if(Info->bProgressive == 1)
			printf("\tProgressive_Sequence : Frame Codeing\n");
		else
			printf("\tProgressive_Sequence : Field Codeing\n");
		printf("\tHsize                : %d\n\tVsize                : %d\n\tFramerate            : %f\n",Info->dwWidth,Info->dwHeight,Info->fFrameRate);*/
		printf("Senqence Header detail:\n\tProfile_id           : %d\t\tLevel_id             : %d\n",Info->dwProfile, Info->dwLevel);
		//if(Info->bProgressive == 1)
		//	printf("\tProgressive_Sequence : Frame Codeing\n");
		//else
		//	printf("\tProgressive_Sequence : Field Codeing\n");
		printf("\tProgressive_Sequence : %d\t", progressive_sequence);
		printf("\tLowDelay             : %d\n",Info->bLowDelay);
		printf("\tHsize                : %d\t\tVsize                : %d\n\tFramerate            : %f",Info->dwWidth,Info->dwHeight,Info->fFrameRate);
		switch(chromat_format){
			case 0:
				printf("\tChromaFormat         : Reservations\n");
				break;
			case 1:
				printf("\tChromaFormat         : 4:2:0\n");
				break;
			case 2:
				printf("\tChromaFormat         : 4:2:2\n");
				break;
			case 3:
				printf("\tChromaFormat         : Reservation\n");
				break;
			default:
				printf("\tChromaFormat         : %d\n",chromat_format);
		}
		switch(sample_precision){
			case 0:
				printf("\tSample_precision     : Forbidden");
				break;
			case 1:
				printf("\tSample_precision     : Chroma Luna 8bit");

				break;
			default:
				printf("\tSample_precision     : %dReservations",chromat_format);
		}
		switch(aspect_ratio){
			case 0:
				printf("\tSAR   : Forbidden\tDAR   : Forbidden\n");
				break;
			case 1:
				printf("\tSAR   :1.0\tDAR  : - \n");
				break;
			case 2:
				printf("\tSAR   : -\tDAR   : 4:3\n");
				break;
			case 3:
				printf("\tSAR   : -\tDAR   : 16:9\n");
				break;
			case 4:
				printf("\tSAR   : -\tDAR   : 2.21:9\n");
			default:
				printf("\tAspect_ratio : %x Reservations\n",aspect_ratio);
		}
		printf("\tMbWidth              : %d\t",Info->dwMbWidth);
		printf("\tMbHeight             : %d\n",Info->dwMbHeight);
#endif
	return dwDataLen-Left;
}

AVS_DWORD SliceHeader(
		const AVS_BYTE* pbData, AVS_DWORD dwDataLen, 
		AVS_DWORD dwMbIndex, AVS_DWORD* pdwBitOffset, 
		STREAMINFO* StrmInfo)
{
	const AVS_BYTE * pbCurrent = pbData;
	AVS_DWORD dwLeft = dwDataLen;
	AVS_DWORD MbWidth = StrmInfo->SeqInfo.dwMbWidth;
	AVS_DWORD MbHeight = StrmInfo->SeqInfo.dwMbHeight;
	AVS_BOOL  slice_weighting_flag = FALSE;
	AVS_DWORD dwMbNum = MbWidth * MbHeight;
	AVS_DWORD BitOffset = 0;
	AVS_DWORD mb_skip_run = 0;
	//AVS_DWORD mb_line_num = u(pbCurrent, &dwBitOffset, dwLeft, 8);
	AVS_DWORD slice_vertical_position_extention = 0;

	// ycb
	AVS_INT i;

	int ii = 0;
	int idx =0;

#if PRINTINFO
	idx = (*pdwBitOffset) / 8 - 4;
	printf("Slice %d Header detail\n",pbCurrent[idx+3]);
	printf("Slice first 16 byte : ");
	
	for(ii = idx; ii < idx + 16; ii++){
		printf("%x ", pbCurrent[ii]);
	}
	printf("\n");
	
#endif
	if (dwMbIndex == 0) {
		if (StrmInfo->SeqInfo.dwWidth > 2800)
			slice_vertical_position_extention = read_bits(pbCurrent, &BitOffset, 3);
		if (!StrmInfo->ImgInfo.bFixedPictureQp) { // ?
			StrmInfo->SlcInfo.bFixedSliceQp = read_bits(pbCurrent, &BitOffset,1);
			StrmInfo->SlcInfo.dwSliceQp = read_bits(pbCurrent, &BitOffset, 6);
		}
	}

	if ((StrmInfo->ImgInfo.dwImageType != I_IMG) || 
	    ((StrmInfo->ImgInfo.bPictureStructure == 0) && 
	     (dwMbIndex >= MbWidth*MbHeight/2))) {
		//    if(StrmInfo->ImgInfo.bSkipModeFlag)
		//      mb_skip_run = ue(pbCurrent, &BitOffset, dwLeft);  
		slice_weighting_flag = read_bits(pbCurrent, &BitOffset, 1);

		if (slice_weighting_flag) {
			for (i = 0; i < 2; i++) {
				StrmInfo->SlcInfo.LumaScale[i] = 
					read_bits(pbCurrent, &BitOffset, 8);
				StrmInfo->SlcInfo.LumaShift[i] = 
					read_bits(pbCurrent, &BitOffset, 8);
				BitOffset += 1; // marker_bit
				StrmInfo->SlcInfo.ChromaScale[i] = 
					read_bits(pbCurrent, &BitOffset, 8);
				StrmInfo->SlcInfo.ChromaShift[i] = 
					read_bits(pbCurrent, &BitOffset, 8);
				//dingo add
					BitOffset += 1; // marker_bit
			}

			StrmInfo->SlcInfo.bMbWeightingFlag = read_bits(pbCurrent, &BitOffset, 8);
		}
	}

	*pdwBitOffset += BitOffset;
#if PRINTINFO
	if (dwMbIndex == 0) {
		if (StrmInfo->SeqInfo.dwWidth > 2800)
			printf("\tSlice vertical position extention : 0x%x\n", slice_vertical_position_extention);
		if (!StrmInfo->ImgInfo.bFixedPictureQp) { // ?
			printf("\tfixed_slice_qp      : %d\n", StrmInfo->SlcInfo.bFixedSliceQp);
			printf("\tslice_qp            : %d\n", StrmInfo->SlcInfo.dwSliceQp);
		}
	}

	if ((StrmInfo->ImgInfo.dwImageType != I_IMG) || 
	    ((StrmInfo->ImgInfo.bPictureStructure == 0) && 
	     (dwMbIndex >= MbWidth*MbHeight/2))) {
		//	printf("\t (PictureType!=I_IMG||(PictureStructure==0&&MbIndex>=MbWidth*MbHeight/2))==true\n");
			printf("\tslice_weighting_flag: 0x%x\n", StrmInfo->SlcInfo.dwSliceQp);

		if (slice_weighting_flag) {
			printf("\t                    :      Ref1    Ref2\n");
			printf("\tluma_scale          :      %d      %d\n", StrmInfo->SlcInfo.LumaScale[0],StrmInfo->SlcInfo.LumaScale[1]);
			printf("\tluma_shift          :      %d      %d\n", StrmInfo->SlcInfo.LumaShift[0],StrmInfo->SlcInfo.LumaShift[1]);
			printf("\tchroma_scale        :      %d      %d\n", StrmInfo->SlcInfo.ChromaScale[0],StrmInfo->SlcInfo.ChromaScale[1]);
			printf("\tchroma_shift        :      %d      %d\n", StrmInfo->SlcInfo.ChromaShift[0],StrmInfo->SlcInfo.ChromaShift[1]);
			}
		printf("\tmb_weighting_flag   : %d\n", StrmInfo->SlcInfo.bMbWeightingFlag);
	}
#endif
	return AVS_NOERROR;
}

AVS_DWORD GetImgHeaderInfo(
		const AVS_BYTE* pbData,AVS_DWORD dwDataLen, 
		AVS_DWORD* dwBitoffset, STREAMINFO* Info)
{
	const AVS_BYTE * pbCurrent = pbData;
	AVS_DWORD bitOffset = 32;
	AVS_DWORD dwCode = *(AVS_DWORD *) pbCurrent;

	// ycb
	AVS_DWORD bbv_dwlay;
	AVS_BOOL time_code_flag;
	AVS_DWORD time_code;
	AVS_DWORD picture_distance;
	AVS_DWORD bbv_check_times;
	AVS_BOOL progressive_frame;
	AVS_BOOL picture_structure;
	AVS_BOOL top_field_first;
	AVS_BOOL repeat_first_field;
	AVS_BOOL fixed_picture_qp;
	AVS_DWORD picture_qp;
	AVS_BOOL skip_mode_flag;
	AVS_DWORD alpha_c_offset;
	AVS_DWORD beta_offset;
	AVS_BOOL loop_filter_disable;
	IMAGEINFO* imgInfo;
	AVS_DWORD picture_coding_type;
	AVS_BOOL advanced_pred_mode_disable;
	AVS_BOOL picture_reference_flag;
	AVS_BOOL loop_filter_parameter_flag;

	int ii;
	int marker_bit;


	if (DWORD_SWAP(dwCode) == I_FRAME_START_CODE) {
		bbv_dwlay = read_bits(pbCurrent, &bitOffset, 16);
		time_code_flag = read_bits(pbCurrent, &bitOffset, 1);
		time_code = 0;
		if (time_code_flag == 1)
			time_code = read_bits(pbCurrent, &bitOffset, 24);
//		marker_bit = read_bits(pbCurrent, &bitOffset, 1);
//		bitOffset++;

		picture_distance = read_bits(pbCurrent, &bitOffset, 8);

		bbv_check_times = 0;
		if (Info->SeqInfo.bLowDelay)
			bbv_check_times = ue(pbData, &bitOffset, dwDataLen);

		progressive_frame = read_bits(pbCurrent, &bitOffset, 1);
		picture_structure = FALSE;
		if (progressive_frame == 0)
			picture_structure = read_bits(pbCurrent, &bitOffset, 1);
		else 
			picture_structure = 1;

		top_field_first = read_bits(pbCurrent, &bitOffset, 1);
		repeat_first_field = read_bits(pbCurrent, &bitOffset, 1);
		fixed_picture_qp = read_bits(pbCurrent, &bitOffset, 1);
		picture_qp = read_bits(pbCurrent, &bitOffset, 6);
		skip_mode_flag = 0;
		if (progressive_frame == 0) {
			if (picture_structure == 0)
				skip_mode_flag = read_bits(pbCurrent, &bitOffset, 1);
		}
		bitOffset += 4; /* reserved_bits */
		alpha_c_offset = 0;
		beta_offset = 0;
		loop_filter_disable = read_bits(pbCurrent, &bitOffset, 1);
		if (! loop_filter_disable) {
			AVS_BOOL loop_filter_parameter_flag = read_bits(pbCurrent, &bitOffset, 1);
			if (loop_filter_parameter_flag) {
				alpha_c_offset = se(pbCurrent, &bitOffset, dwDataLen);
				beta_offset = se(pbCurrent, &bitOffset, dwDataLen);
			}
		}
	
		imgInfo = &(Info->ImgInfo);
		imgInfo->dwImageType = I_IMG;
		imgInfo->dwPictureDistance = picture_distance;
		imgInfo->bProgressiveFrame = progressive_frame;
		imgInfo->bPictureStructure = picture_structure;
		imgInfo->bTopFieldFirst = top_field_first;
		imgInfo->bFixedPictureQp = fixed_picture_qp;
		imgInfo->bRepeatFirstField = repeat_first_field;
		imgInfo->dwPictureQp = picture_qp;
		imgInfo->bSkipModeFlag = skip_mode_flag;
		imgInfo->bLoopFilterDisable = loop_filter_disable;
		imgInfo->iAlphaCOffset = alpha_c_offset;
		imgInfo->iBetaOffset = beta_offset;
		*dwBitoffset = bitOffset;
#if PRINTINFO
		printf("IFrame Header Detail\n");
		printf("\timgInfo.dwImageType : I_IMG");
		printf("\tBBV delay           : 0x%x\n", bbv_dwlay);
		printf("\tTime code Flag      : %d\n", time_code_flag);
			if(time_code_flag == 1)
		printf("\tTime code           : %d\n", time_code);
		printf("\tPicture distance    : %d\t", picture_distance);
		if(Info->SeqInfo.bLowDelay)
			printf("\tbbv check times    : %d\n", bbv_check_times);

		printf("\tProgressive frame   : %d\n", progressive_frame);
		if (progressive_frame == 0)
			printf("\tPicture structure   : %d\t", picture_structure);
		else
			printf("\tPicture structure   : 1\t");
		printf("\tTop field first     : %d\n", top_field_first);
		printf("\tRepeat first field  : %d\t", repeat_first_field);
		printf("\tFixed picture qp    : %d\n", fixed_picture_qp);
		printf("\tPicture qp          : %d", picture_qp);
		if (progressive_frame == 0) {
			if (picture_structure == 0)
				printf("\tSkip mode flag      : %d\n", skip_mode_flag);		
		}
		printf("\tLoop filter disable : %d\n", loop_filter_disable);
		printf("\tAlpha c offset      : %d\t", alpha_c_offset);
		printf("\tBeta offset         : %d\n\n", beta_offset);
#endif
		return AVS_NOERROR;
	}
	else if (DWORD_SWAP(dwCode) == PB_FRAME_START_CODE) {
		bbv_dwlay = read_bits(pbCurrent, &bitOffset, 16);
		picture_coding_type = read_bits(pbCurrent, &bitOffset, 2);
		picture_distance = read_bits(pbCurrent, &bitOffset, 8);

		bbv_check_times = 0;
		if (Info->SeqInfo.bLowDelay)
			bbv_check_times = ue(pbData, &bitOffset, dwDataLen);

		progressive_frame = read_bits(pbCurrent, &bitOffset, 1);
		picture_structure = 0;
		if (progressive_frame == 0) {
			picture_structure = read_bits(pbCurrent, &bitOffset, 1);
			if (! picture_structure)
				advanced_pred_mode_disable = read_bits(pbCurrent, &bitOffset, 1);
		}
		else {
			picture_structure = TRUE;
		}
		top_field_first = read_bits(pbCurrent, &bitOffset, 1);
		repeat_first_field = read_bits(pbCurrent, &bitOffset, 1);
		fixed_picture_qp = read_bits(pbCurrent, &bitOffset, 1);
		picture_qp = read_bits(pbCurrent, &bitOffset, 6);

		picture_reference_flag = FALSE;
		if (! (picture_coding_type == 2 && picture_structure == 1))
			picture_reference_flag = read_bits(pbCurrent, &bitOffset, 1);

		bitOffset += 4; //reserved_bits

		skip_mode_flag = read_bits(pbCurrent, &bitOffset, 1);
		loop_filter_disable = read_bits(pbCurrent, &bitOffset, 1);
		loop_filter_parameter_flag = FALSE;
		alpha_c_offset = 0;
		beta_offset = 0;
		if (! loop_filter_disable) {
			loop_filter_parameter_flag = read_bits(pbCurrent, &bitOffset, 1);
			if (loop_filter_parameter_flag) {
				alpha_c_offset = se(pbData, &bitOffset, dwDataLen);
				beta_offset = se(pbData, &bitOffset, dwDataLen);
			}
		}

		imgInfo = &(Info->ImgInfo);
		if (picture_coding_type == 1)
			imgInfo->dwImageType = P_IMG;
		else
			imgInfo->dwImageType = B_IMG;
		imgInfo->bFixedPictureQp = fixed_picture_qp;
		imgInfo->bLoopFilterDisable = loop_filter_disable;
		imgInfo->bPictureReferenceFlag = picture_reference_flag;
		imgInfo->bPictureStructure = picture_structure;
		imgInfo->bProgressiveFrame = progressive_frame;
		imgInfo->bRepeatFirstField = repeat_first_field;
		imgInfo->bSkipModeFlag = skip_mode_flag;
		imgInfo->bTopFieldFirst = top_field_first;
		imgInfo->iAlphaCOffset = alpha_c_offset;
		imgInfo->iBetaOffset = beta_offset;
		imgInfo->dwPictureDistance = picture_distance;
		imgInfo->dwPictureQp = picture_qp;

		*dwBitoffset = bitOffset;
#if PRINTINFO

		if (picture_coding_type == 1)
			printf("\timgInfo.dwImageType : P_IMG\n");
		else
			printf("\timgInfo.dwImageType : B_IMG\n");
		printf("PBFrame Header Detail\n");
		printf("\tBBV delay           : 0x%x\n", bbv_dwlay);
		printf("\tpicture coding type : %d\n", picture_coding_type);
		printf("\tPicture distance    : %d\n", picture_distance);
		if(Info->SeqInfo.bLowDelay)
			printf("\tbbv check times     : %d\n", bbv_check_times);
		printf("\tProgressive frame   : %d\n", progressive_frame);
		if (progressive_frame == 0){
			printf("\tPicture structure   : %d\n", picture_structure);
			if (! picture_structure)
				printf("\tAdvPredModedisable  : %d\n", advanced_pred_mode_disable);
		}
		else
			printf("\tpicture_structure   : 1\n");
		printf("\ttop field first     : %d\n", top_field_first);
		printf("\tRepeat first field  : %d\n", repeat_first_field);
		printf("\tFixed picture qp    : %d\n", fixed_picture_qp);
		printf("\tPicture qp          : %d\n", picture_qp);
		if (! (picture_coding_type == 2 && picture_structure == 1))
		printf("\tIMG reference flag  : %d\n", picture_reference_flag);
			picture_reference_flag = read_bits(pbCurrent, &bitOffset, 1);



		printf("\tSkip mode flag      : %d\n", skip_mode_flag);		
		printf("\tLoop filter disable : %d\n", loop_filter_disable);
		printf("\tAlpha c offset      : %d\n", alpha_c_offset);
		printf("\tBeta offset         : %d\n\n", beta_offset);
#endif
		return AVS_NOERROR;
	}
	else {
		return AVS_INVALID_PIC_START_CODE;
	}
}

/**
 * Function: Find next start code.
 */
AVS_BOOL FindNextStartCode(const AVS_BYTE* pbData, AVS_DWORD dwDataLen, AVS_DWORD* dwLeft)
{
	const AVS_BYTE* pbCurrent = pbData+4;
	AVS_DWORD Left = dwDataLen-4;

	while (Left>4 && 
	       (*(AVS_DWORD *) pbCurrent & 0x00FFFFFF) != 0x00010000) {
		pbCurrent ++;
		Left --;
	}

	if (Left > 4) {
		*dwLeft = Left;
		return TRUE;
	}
	return FALSE;
}

